package il.ac.technion.wiki.api.wikidocument;

import il.ac.technion.wiki.api.wikidocument.content.ContentImporter;
import il.ac.technion.wiki.api.wikidocument.content.StringContentImporter;
import il.ac.technion.wiki.impl.logger.LogFactory;

import java.io.InvalidObjectException;
import java.util.Map;
import java.util.Stack;

import org.apache.log4j.Logger;

public class WikiDocument implements IWikiDocument {
	Stack<VersionData> versions = new Stack<VersionData>();
	private String title = null;
	private Logger logger = LogFactory.getLog(this.getClass());

	public WikiDocument(String title, String content) {
		if ((title == null) || (content == null))
			throw new IllegalArgumentException("null parameter");
		if ((title == "") || (content == ""))
			throw new IllegalArgumentException("empty title or content");
		this.title = title;
		versions.add(new VersionData(0, new StringContentImporter(content)));
	}

	public WikiDocument(String title, String content, Map<String, String> metadata) {
		if ((title == null) || (content == null) || (metadata == null))
			throw new IllegalArgumentException("null parameter");
		if ((title == "") || (content == ""))
			throw new IllegalArgumentException("empty title or content");
		this.title = title;
		versions.add(new VersionData(0, new StringContentImporter(content),
				metadata));
	}

	public WikiDocument(String title, ContentImporter ci) {
		if ((title == null) || (ci == null))
			throw new IllegalArgumentException("null parameter");
		if ((title == "") || (ci.asString() == ""))
			throw new IllegalArgumentException("empty title or content");
		this.title = title;
		versions.add(new VersionData(0, ci));
	}

	public WikiDocument(String title, ContentImporter ci, Map<String, String> metadata) {
		if ((title == null) || (ci == null) || (metadata == null))
			throw new IllegalArgumentException("null parameter");
		if ((title == "") || (ci.asString() == ""))
			throw new IllegalArgumentException("empty title or content");
		this.title = title;
		versions.add(new VersionData(0, ci, metadata));
	}

	@Override
	public String getTitle() {
		return this.title;
	}

	@Override
	public String getContent() {
		return versions.lastElement().getContent();
	}

	@Override
	public void updateContent(String newContent) {
		if (newContent == null)
			throw new IllegalArgumentException("null parameter");
		if (newContent == "")
			throw new IllegalArgumentException("empty content");
		if (getCurrentMetadata() != null)
			versions.add(new VersionData(getCurrentVersion() + 1,
					new StringContentImporter(newContent), getCurrentMetadata()));
		else
			versions.add(new VersionData(getCurrentVersion() + 1,
					new StringContentImporter(newContent)));
	}

	@Override
	public void updateContent(ContentImporter ci) {
		if (ci == null)
			throw new IllegalArgumentException("null parameter");
		if (ci.asString() == "")
			throw new IllegalArgumentException("empty content");
		if (getCurrentMetadata() != null)
			versions.add(new VersionData(getCurrentVersion() + 1, ci,
					getCurrentMetadata()));
		else
			versions.add(new VersionData(getCurrentVersion() + 1, ci));
	}

	@Override
	public void updateMetadata(Map<String, String> metadata) {
		versions.add(new VersionData(getCurrentVersion() + 1,
				getContentImporter(), metadata));
	}

	@Override
	public Map<String, String> getCurrentMetadata() {
		return versions.lastElement().getMetadata();
	}

	@Override
	public Integer getCurrentVersion() {
		return versions.lastElement().getVersion();
	}

	@Override
	public void backToVersion(Integer version) throws InvalidObjectException {
		if (getCurrentVersion() == version)
			return;
		if (getVersion(version) != null){
			while (versions.lastElement().getVersion() != version)
				versions.pop();
		}
	}

	@Override
	public IWikiDocument viewVersion(Integer version)
			throws InvalidObjectException {
		VersionData ver = null;
		if ((ver  = getVersion(version)) == null)
			return null;
		Map<String, String> metadata = ver.getMetadata();
		if (metadata == null) 
			return new WikiDocument(title, ver.getContentImporter());
		return new WikiDocument(title, ver.getContentImporter(), metadata);
	}
	
	private VersionData getVersion(Integer version) throws InvalidObjectException {
		if (version < 0)
			throw new IllegalArgumentException(
					"versions should be bigger than 0");
		VersionData ver = null;
		if ((ver = versionExists(version)) == null) {
			logger.error("back to version that doesn't exists: " + version);
			throw new InvalidObjectException("Version doesn't exists");
		}
		return ver;
	}

	private VersionData versionExists(Integer ver) {
		for (VersionData vd : versions) {
			if (vd.getVersion() == ver)
				return vd;
		}
		return null;
	}

	private ContentImporter getContentImporter() {
		return versions.lastElement().getContentImporter();
	}
}
